home *** CD-ROM | disk | FTP | other *** search
/ How to Get Online 1996 Spring / HOW2GON.ISO / mac / Desktop Folder / How To Get Online / SERVERS / CGI / dbcgi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-01  |  39.4 KB  |  1 lines  |  [TEXT/MMCC]

  1. /* * This file forms part of CorVu dbCGI * * CorVu dbCGI is Copyright (C) 1995  CorVu Pty Ltd. * Written by Troy Rollo * * CorVu dbCGI is free software. It may be modified and redistributed under * the terms of the CorVu General Public License, either version 1, or, at * your option, any later version. Ensure that you read this license before * modifying or redistributing the software. * * THIS PROGRAM IS PROVIDED "AS IS" WITH NO WORRANTY OF ANY KIND. YOU USE * THIS PROGRAM ENTIRELY AT YOUR OWN RISK. NEITHER CORVU, NOR ANY OTHER * PARTY MAY BE HELD RESPONSIBLE FOR ANY DAMAGES ARISING FROM YOUR USE OR * MISUSE OF THIS PROGRAM. */#include "dbcgi.h"#if defined(__sparc__) && defined(__sun__) && \    defined(__GNUC__) && defined(__svr4__)    unsigned long long    __cg92_used = 0x9de3bfa011000141ll;#endifFILE    *fpOutput;dbw_connection *pconnList = 0;long    nMaxBlob = 32768l;typedef struct{    char    *pchCommand;    void    (*fcnHandler)(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);} dbw_commands;extern    void    DBInit(dbw_value *pval);extern    void    DBUnInit(dbw_value *pval);extern    void    DBConnect(dbw_value *pval);extern    void    DBDisconnect(dbw_value *pval);extern    void    DBQuery(dbw_value *pval);extern    void    DBExecute(dbw_value *pval);void    DoDBInit(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void    DoDBUnInit(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void    DoDBConnect(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void    DoDBDisconnect(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void    DoDBQuery(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void    DoDBExecute(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void    DoFormat(dbw_buf pchBuffer, long ibytes, dbw_buf pchConnID);void    DoHeadings(dbw_buf pchBuffer, long ibytes, dbw_buf pchConnID);void    DoError(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void    DoValidateArgs(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void    DoValidateForm(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);dbw_buf    ConvertFormat(dbw_buf pchSrc);void FormattedWrite(dbw_buf pchFormat);dbw_commands cmd_list[] ={    {    "init",        DoDBInit    },    {    "uninit",    DoDBUnInit    },    {    "connect",    DoDBConnect    },    {    "disconnect",    DoDBDisconnect    },    {    "query",    DoDBQuery    },    {    "execute",    DoDBExecute    },    {    "format",    DoFormat    },    {    "headings",    DoHeadings    },    {    "error",    DoError        },    {    "valarg",    DoValidateArgs    },    {    "valform",    DoValidateForm    }};dbw_buf    pchFormat = 0;dbw_buf pchError = 0;dbw_buf pchHeadings = 0;dbw_result *prsltCurrent = 0;int    *piAreRepeats = 0;int    iColsCurrent = 0;dbw_result *prsltPrevious = 0;int    nColsPrevious = 0;dbw_buf pchSQLCurrent = 0;dbw_buf pchErrMsgCurrent = 0;long    iErrNoCurrent = 0;char    **ppchArgList;int    nArgs;long    iPid;long    iSequence = 0;dbw_value *pvalForm = 0;char    *pchValueCurrent = 0;int    iEscaping = 0;int    iInternal = 0;intMustEscape(char c){    return (!isalpha(c) && !isdigit(c));}static char achHexDigits[] = "0123456789abcdef";char *EscapedValue(char c){    static char achEscaped[4];    if (MustEscape(c))    {        achEscaped[0] = '%';        achEscaped[1] = achHexDigits[(unsigned char) c / 16];        achEscaped[2] = achHexDigits[(unsigned char) c % 16];        achEscaped[3] = 0;    }    else    {        achEscaped[0] = c;        achEscaped[1] = 0;    }    return achEscaped;}intHexToDec(char c){    if (c >= '0' && c <= '9')        return c - '0';    if (c >= 'A' && c <= 'F')        return c - 'A' + 10;    if (c >= 'a' && c <= 'f')        return c - 'a' + 10;    return 0;}charGetNextEscape(char **ppchData){    char    *pch = *ppchData;    if (*pch == '%' && pch[1] && pch[2])    {        *ppchData += 3;        return HexToDec(pch[1]) * 16 + HexToDec(pch[2]);    }    else if (*pch == '+')    {        (*ppchData)++;        return ' ';    }    else    {        (*ppchData)++;        return *pch;    }}voidShowError(char *pch){    fprintf(fpOutput, "%s: %s\r\n", pch, sys_errlist[errno]);}/* * Case insensitive comparison. Unlike strcmp & siblings, * this gives a boolean result. */intStringCompare(    dbw_buf    pch1,        dbw_buf    pch2,        long    iBytes){    while (iBytes--)    {        if (*pch1 != *pch2++)            return 0;        if (!*pch1++)            return 1;    }    return 1;}/* String compare that uses dbw_buf types */longStringLength(dbw_buf pchStr){    long    iLength = 0;    while (*pchStr++)        iLength++;    return iLength;}voidStringCopy(dbw_buf pchDest, dbw_buf pchSrc){    while ((*pchDest++ = *pchSrc++) != 0);}dbw_bufStringDuplicate(dbw_buf pchSource){    dbw_buf pchDest = new2(char, StringLength(pchSource) + 1);    StringCopy(pchDest, pchSource);    return pchDest;}/* * Search for commands in the buffer and act on them */voidProcessBuffer(    dbw_buf    pchBuffer,        long    iBytes,        int    iTop){    dbw_buf    pchNow, pchCommand, pchConnection;    long    iLoc = 0;    int    nWritten;    int    nWrite;    int    i;    while (iBytes)    {        iLoc = 0;        pchNow = pchBuffer;        while (iLoc < iBytes - 5 &&               (*pchNow != '<' ||            !StringCompare(pchNow, "<sql ", 5)))        {            iLoc++;            pchNow++;        }        if (iLoc >= iBytes - 5)        {            pchNow += iBytes - iLoc;            iLoc = iBytes;        }        if (iLoc > 0)        {            iBytes -= iLoc;            *pchNow = 0;            FormattedWrite(pchBuffer);            pchBuffer = pchNow;        }        if (iBytes > 0)        {            pchCommand = pchBuffer + 5;            iBytes -= 5;            iLoc = 0;            for (pchBuffer = pchCommand;                 iLoc != iBytes && *pchBuffer != '>';                 pchBuffer++, iLoc++);            if (iLoc == iBytes)                return;            *pchBuffer++ = '\0';            iBytes -= iLoc + 1;            for (pchConnection = pchCommand;                 *pchConnection && *pchConnection != ' ';                 pchConnection++);            if (*pchConnection)                *pchConnection++ = '\0';            iLoc = 0;            pchNow = pchBuffer;            while (iLoc < iBytes - 6 &&                   (*pchNow != '<' ||                !StringCompare(pchNow, "</sql>", 6)))            {                iLoc++;                pchNow++;            }            if (iLoc >= iBytes - 6)            {                pchNow += iBytes - iLoc;                iLoc = iBytes;            }            else            {                *pchNow = 0;            }            for (i = 0; i < rangeof(cmd_list); i++)            {                if (StringCompare(cmd_list[i].pchCommand, pchCommand, StringLength(pchCommand) + 1))                {                    (*cmd_list[i].fcnHandler)(pchBuffer, iLoc, pchConnection);                    break;                }            }            if (iLoc + 6 >= iBytes)            {                iBytes = 0;                pchBuffer = pchNow;            }            else            {                iBytes -= iLoc + 6;                pchBuffer = pchNow + 6;            }        }    }    return;}/* * Read a file in, and let the games begin. * We read the file into memory in its entirity because we * expect that it will be a reasonable size to do so, and * because that simplifies processing. */voidReadFile(char *pchFileName){    struct    stat    sbuf;    dbw_buf pchBuffer, pchNow;    FILE    *fp;    long    iBytes;    int    iRead;    if (stat(pchFileName, &sbuf) == -1)    {        ShowError(pchFileName);        return;    }    fp = fopen(pchFileName, "r");    pchBuffer = new2(char, sbuf.st_size + 1);    if (!pchBuffer)    {        fprintf(fpOutput,            "<TITLE>Error reading %s</TITLE>\r\nUnable to allocate %ld bytes\n",            pchFileName, sbuf.st_size);        return;    }    pchNow = pchBuffer;    iBytes = 0;    while ((iRead = ((sbuf.st_size - iBytes > READ_SIZE) ?                 READ_SIZE : ((int) (sbuf.st_size - iBytes)))) &&           (iRead = fread(pchNow, 1, iRead, fp)) > 0)    {        iBytes += iRead;        pchNow += iRead;    }    fclose(fp);    if (!iBytes)    {        fprintf(fpOutput,            "<TITLE>Error reading %s</TITLE>\r\nEmpty file\n",            pchFileName);        free(pchBuffer);        return;    }    pchBuffer[iBytes] = 0;    ProcessBuffer(pchBuffer, iBytes, 1);    free(pchBuffer);    return;}dbw_value *GetKeys(    dbw_buf pchBuffer,        long    iBytes,        dbw_buf pchConnID){    dbw_value *pvalList = 0, *pvalNew;    dbw_buf    pchNow, pchValue, pchEqual;    long    iNow;    if (pchConnID && *pchConnID)    {        pvalNew = new(dbw_value);        pvalNew->pchKey = "ConnID";        pvalNew->pchValue = pchConnID;        pvalNew->pvalNext = pvalList;        pvalList = pvalNew;    }    while (iBytes)    {        for (pchNow = pchBuffer, iNow = 0;             *pchNow != '\n' && iNow < iBytes;             pchNow++, iNow++);        if (iNow < iBytes)            *pchNow++ = '\0';        if (!*pchBuffer)        {            pchBuffer++;            iBytes--;            continue;        }        for (pchEqual = pchBuffer;             *pchEqual && *pchEqual != '=';             pchEqual++);        if (*pchEqual)        {            *pchEqual++ = 0;            pvalNew = new(dbw_value);            pvalNew->pchKey = pchBuffer;            pvalNew->pchValue = pchEqual;            pvalNew->pvalNext = pvalList;            pvalList = pvalNew;        }        iBytes -= iNow;        pchBuffer = pchNow;    }    return pvalList;}dbw_value *GetNamedKey(    dbw_buf pchBuffer,        long    iBytes,        dbw_buf pchKey,        dbw_buf pchConnID){    dbw_value *pvalList = 0, *pvalNew;    if (pchConnID && *pchConnID)    {        pvalNew = new(dbw_value);        pvalNew->pchKey = "ConnID";        pvalNew->pchValue = pchConnID;        pvalNew->pvalNext = pvalList;        pvalList = pvalNew;    }    if (pchBuffer && *pchBuffer)    {        pvalNew = new(dbw_value);        pvalNew->pchKey = pchKey;        pvalNew->pchValue = pchBuffer;        pvalNew->pvalNext = pvalList;        pvalList = pvalNew;    }    return pvalList;}voidFreeKeys(dbw_value *pvalList){    dbw_value *pvalNext;    while (pvalList)    {        pvalNext = pvalList->pvalNext;        free(pvalList);        pvalList = pvalNext;    }}voidDoDBInit(    dbw_buf pchBuffer,        long iBytes,        dbw_buf pchConnID){    dbw_buf pchBuf = ConvertFormat(pchBuffer);    dbw_value *pvalList = GetKeys(pchBuf, iBytes, pchConnID);    char    *pchMaxBlob = GetValue(pvalList, "MAXBLOB");    if (pchMaxBlob)        nMaxBlob = atoi(pchMaxBlob);    else        nMaxBlob = 32768l;    DBInit(pvalList);    FreeKeys(pvalList);    free(pchBuf);}voidDoDBUnInit(    dbw_buf pchBuffer,        long iBytes,        dbw_buf pchConnID){    dbw_buf pchBuf = ConvertFormat(pchBuffer);    dbw_value *pvalList = GetKeys(pchBuf, iBytes, pchConnID);    DBUnInit(pvalList);    FreeKeys(pvalList);    free(pchBuf);}voidDoDBConnect(    dbw_buf pchBuffer,        long iBytes,        dbw_buf pchConnID){    dbw_buf pchBuf = ConvertFormat(pchBuffer);    dbw_value *pvalList = GetKeys(pchBuf, iBytes, pchConnID);    DBConnect(pvalList);    FreeKeys(pvalList);    free(pchBuf);}voidDoDBDisconnect(    dbw_buf pchBuffer,        long iBytes,        dbw_buf pchConnID){    dbw_buf pchBuf = ConvertFormat(pchBuffer);    dbw_value *pvalList = GetKeys(pchBuf, iBytes, pchConnID);    DBDisconnect(pvalList);    FreeKeys(pvalList);    free(pchBuf);}voidDoDBQuery(    dbw_buf pchBuffer,        long iBytes,        dbw_buf pchConnID){    int    i;    dbw_buf pchBuf = ConvertFormat(pchBuffer);    dbw_value *pvalList = GetNamedKey(pchBuf, iBytes, "Query", pchConnID);    DBQuery(pvalList);    FreeKeys(pvalList);    free(pchBuf);    if (prsltPrevious)    {        for (i = 0; i < nColsPrevious; i++)            if (prsltPrevious[i].pchCharValue)                free(prsltPrevious[i].pchCharValue);        free(prsltPrevious);        prsltPrevious = 0;    }    if (piAreRepeats)    {        free(piAreRepeats);        piAreRepeats = 0;    }}voidDoDBExecute(    dbw_buf pchBuffer,        long iBytes,        dbw_buf pchConnID){    dbw_buf pchBuf = ConvertFormat(pchBuffer);    dbw_value *pvalList = GetNamedKey(pchBuf, iBytes, "Query", pchConnID);    DBExecute(pvalList);    FreeKeys(pvalList);    free(pchBuf);}voidDoFormat(    dbw_buf pchBuffer,        long iBytes,        dbw_buf pchConnID){    pchFormat = pchBuffer;}voidDoHeadings(    dbw_buf pchBuffer,        long iBytes,        dbw_buf pchConnID){    pchHeadings = pchBuffer;}voidDoError(    dbw_buf pchBuffer,        long iBytes,        dbw_buf pchConnID){    pchError = pchBuffer;}char    NextCChar(char **cPtr){    char    c;    c = *(*cPtr)++;    if (c == '\\' && **cPtr)    {        c = *(*cPtr)++;        if (c == '\\')            c = '\\';        else if (c == 'n')            c = '\n';        else if (c == 'r')            c = '\r';        else if (c == 'b')            c = '\b';        else if (c == 't')            c = '\t';        else if (c >= '0' && c <= '7')        {            int i;            i = (c - '0');            c = **cPtr;            if (c >= '0' && c <= '7')            {                (*cPtr)++;                i *= 8;                i += c  - '0';                c = **cPtr;                if (c >= '0' && c <= '7')                {                    i *= 8;                    (*cPtr)++;                    i += c - '0';                }            }            c = (char) i;        }    }    return c;}voidFailValidate(    dbw_value *pvalRules,        char    *pchValue,        char    *pchFormat){    char    *pchForm2 = GetValue(pvalRules, "FORMAT");    if (pchForm2)        pchFormat = pchForm2;    pchValueCurrent = pchValue;    FormattedWrite(pchFormat);    exit(0);}        voidValidateValue(    char    *pchValue,        dbw_value *pvalRules,        char    *pchItem,        char    *pchFormat){    char    *pchTemp;    char    *c, *c2;    char    cNow;    pchTemp = GetValue(pvalRules, "CLASS");    if (pchTemp)    {        c = pchValue;        if (!strcmp(pchTemp, "NUMERIC"))        {            if (*c == '-' || *c == '+')                c++;            while (*c && isdigit(*c))                c++;            if (*c == '.')                c++;            while (*c && isdigit(*c))                c++;            if (*c)                FailValidate(pvalRules, pchValue, pchFormat);        }        else if (!strcmp(pchTemp, "PLAINTEXT"))        {            while (*c)            {                if (*c < ' ' || *c >= '\177')                    FailValidate(pvalRules, pchValue, pchFormat);                c++;            }        }        else if (!strcmp(pchTemp, "TABBEDTEXT"))        {            while (*c)            {                if ((*c < ' ' && *c != '\t') || *c >= '\177')                    FailValidate(pvalRules, pchValue, pchFormat);                c++;            }        }        FreeString(pchTemp);    }    pchTemp = GetValue(pvalRules, "MAXCHARS");    if (pchTemp)    {        if (strlen(pchValue) > atoi(pchTemp))            FailValidate(pvalRules, pchValue, pchFormat);        FreeString(pchTemp);    }    pchTemp = GetValue(pvalRules, "MINCHARS");    if (pchTemp)    {        if (strlen(pchValue) < atoi(pchTemp))            FailValidate(pvalRules, pchValue, pchFormat);        FreeString(pchTemp);    }    pchTemp = GetValue(pvalRules, "FORBIDDEN");    if (pchTemp)    {        c = pchValue;        c2 = pchTemp;        while (*c2)        {            cNow = NextCChar(&c2);            if (strchr(c, cNow))                FailValidate(pvalRules, pchValue, pchFormat);        }        FreeString(pchTemp);    }    pchTemp = GetValue(pvalRules, "RANGE");    if (pchTemp)    {        c = pchValue;        while (*c)        {            int    iIsOK = 0;            c2 = pchTemp;            while (*c2)            {                cNow = NextCChar(&c2);                if (cNow == *c)                {                    iIsOK = 1;                    break;                }            }            if (!iIsOK)                FailValidate(pvalRules, pchValue, pchFormat);            c++;        }        FreeString(pchTemp);    }}voidDoValidateArgs(    dbw_buf pchBuffer,        long iBytes,        dbw_buf pchConnID){    dbw_value *pvalList = GetKeys(pchBuffer, iBytes, pchConnID);    char    *pchTest = GetValue(pvalList, "ConnID");    int    iArg;    if (pchTest)    {        iArg = atoi(pchTest);        if (iArg >= 1 && iArg <= nArgs)            ValidateValue(ppchArgList[iArg - 1], pvalList,                pchTest,                "<H1>Error</H1>"                "The argument value of %v is invalid<BR>");    }    iArg = atoi(pchTest);    FreeString(pchTest);    FreeKeys(pvalList);}voidDoValidateForm(    dbw_buf pchBuffer,        long iBytes,        dbw_buf pchConnID){    dbw_value *pvalList = GetKeys(pchBuffer, iBytes, pchConnID);    char    *pchTest = GetValue(pvalList, "ConnID");    if (pchTest)    {        char    *pchValue = GetValue(pvalForm, pchTest);        if (pchValue)            ValidateValue(pchValue,                pvalList,                pchTest,                "<H1>Error</H1>"                "The form value of %v is invalid<BR>");    }    FreeString(pchTest);    FreeKeys(pvalList);}typedef struct    __dbw_formdata{    void    (*func)(void *pvDest, char *pchText, int iBytes);    void    *pvDest;} dbw_formdata;typedef struct{    int    iBytes;    int    iLen;    char    *pchData;} dbw_string;voidDataToOutput(void *pvDest, char *pchText, int iBytes){    FILE *fp = (FILE *) pvDest;    fwrite(pchText, 1, iBytes, fp);}voidDataToString(void *pvDest, char *pchText, int iBytes){    dbw_string *pstr = (dbw_string *) pvDest;    if (iBytes + pstr->iLen >= pstr->iBytes)    {        char    *pchNew;        int    iNew;        int    iMod;        iNew = pstr->iLen + iBytes + 1;        iMod = iNew % 256;        if (iMod)            iNew += 256 - iMod;        pchNew = new2(char, iNew);        if (pstr->pchData)        {            memcpy(pchNew, pstr->pchData, pstr->iLen);            free(pstr->pchData);        }        pstr->pchData = pchNew;        pstr->iBytes = iNew;    }    memcpy(pstr->pchData + pstr->iLen, pchText, iBytes);    pstr->iLen += iBytes;    pstr->pchData[pstr->iLen] = 0;}voidEscapedDataToOutput(void *pvDest, char *pchText, int iBytes){    int    i = 0;    dbw_formdata *pfdata = (dbw_formdata *) pvDest;    char    achData[4];    while (i < iBytes)    {        if (MustEscape(pchText[i]))        {            if (i)            {                (*pfdata->func)(pfdata->pvDest, pchText, i);                iBytes -= i;                pchText += i;            }            strcpy(achData, EscapedValue(pchText[0]));            (*pfdata->func)(pfdata->pvDest, achData, 3);            pchText++;            iBytes--;            i = 0;        }        else        {            i++;        }    }    if (iBytes)        (*pfdata->func)(pfdata->pvDest, pchText, iBytes);}voidDoubleUpSQuotes(void *pvDest, char *pchText, int iBytes){    int    i = 0;    dbw_formdata *pfdata = (dbw_formdata *) pvDest;    char    achData[4];    while (i < iBytes)    {        if (pchText[i] == '\'')        {            if (i)            {                (*pfdata->func)(pfdata->pvDest, pchText, i);                iBytes -= i;                pchText += i;            }            strcpy(achData, EscapedValue(pchText[0]));            (*pfdata->func)(pfdata->pvDest, "''", 2);            pchText++;            iBytes--;            i = 0;        }        else        {            i++;        }    }    if (iBytes)        (*pfdata->func)(pfdata->pvDest, pchText, iBytes);}voidDoubleUpDQuotes(void *pvDest, char *pchText, int iBytes){    int    i = 0;    dbw_formdata *pfdata = (dbw_formdata *) pvDest;    char    achData[4];    while (i < iBytes)    {        if (pchText[i] == '"')        {            if (i)            {                (*pfdata->func)(pfdata->pvDest, pchText, i);                iBytes -= i;                pchText += i;            }            strcpy(achData, EscapedValue(pchText[0]));            (*pfdata->func)(pfdata->pvDest, "\"\"", 2);            pchText++;            iBytes--;            i = 0;        }        else        {            i++;        }    }    if (iBytes)        (*pfdata->func)(pfdata->pvDest, pchText, iBytes);}voidDoubleUpBackSlashes(void *pvDest, char *pchText, int iBytes){    int    i = 0;    dbw_formdata *pfdata = (dbw_formdata *) pvDest;    char    achData[4];    while (i < iBytes)    {        if (pchText[i] == '\\')        {            if (i)            {                (*pfdata->func)(pfdata->pvDest, pchText, i);                iBytes -= i;                pchText += i;            }            strcpy(achData, EscapedValue(pchText[0]));            (*pfdata->func)(pfdata->pvDest, "\\\\", 2);            pchText++;            iBytes--;            i = 0;        }        else        {            i++;        }    }    if (iBytes)        (*pfdata->func)(pfdata->pvDest, pchText, iBytes);}voidPadSpaces(dbw_formdata *pfdata,    int iSpaces){    while (iSpaces > 0)    {        (*pfdata->func)(pfdata->pvDest,            "                    ",            iSpaces > 20 ? 20 : iSpaces);        iSpaces -= 20;    }}voidFormatChar(dbw_formdata *pfdata,         char *pchData,         int iWidth,         int iPrec){    int    iLen = strlen(pchData);    int    iNow = 0;    if (iPrec > 0 && iLen > iPrec)        iLen = iPrec;    iPrec = iLen;    /* If we are inside an HTML escaping expansion, or     * we are converting values for internal use by dbCGI,     * don't convert line breaks or HTML special characters.     */    if (iEscaping || iInternal)        iNow = iPrec;    while (iNow < iPrec)    {        if (pchData[iNow] == '\r' || pchData[iNow] == '\n')        {            if (iNow)                (*pfdata->func)(pfdata->pvDest, pchData, iNow);            pchData += iNow;            iPrec -= iNow;            iNow = 0;            (*pfdata->func)(pfdata->pvDest, "<BR>\r\n", 6);            if (pchData[0] == '\r' &&                iPrec > 1 &&                pchData[1] == '\n')            {                pchData += 2;                iPrec -= 2;            }            else            {                pchData++;                iPrec--;            }        }        else if (pchData[iNow] == '<' ||            pchData[iNow] == '>' ||            pchData[iNow] == '&' ||            pchData[iNow] == '"')        {            if (iNow)                (*pfdata->func)(pfdata->pvDest, pchData, iNow);            if (pchData[iNow] == '<')                (*pfdata->func)(pfdata->pvDest, "<", 4);            else if (pchData[iNow] == '>')                (*pfdata->func)(pfdata->pvDest, ">", 4);            else if (pchData[iNow] == '"')                (*pfdata->func)(pfdata->pvDest, """, 6);            else if (pchData[iNow] == '&')                (*pfdata->func)(pfdata->pvDest, "&", 5);            pchData += iNow + 1;            iPrec -= iNow + 1;            iNow = 0;        }        else        {            iNow++;        }    }    if (iPrec)        (*pfdata->func)(pfdata->pvDest, pchData, iPrec);    if (iWidth > iLen)        PadSpaces(pfdata, iWidth - iLen);}voidFormatFloat(dbw_formdata *pfdata,        double    fValue,        int    iWidth,        int    iPrec){    static    char    achFloatBuf[1024];    sprintf(achFloatBuf, "%*.*f", iWidth, iPrec, fValue);    (*pfdata->func)(pfdata->pvDest, achFloatBuf, strlen(achFloatBuf));}voidFormatInteger(dbw_formdata *pfdata,        long    iValue,        int iWidth,        int iPrec){    long    iModulus = 1;    long    iFraction;    int    i = iPrec;    int    iCharacters;    char    achBuffer[50];    long    iAbsValue;    if (iPrec > 20)        return;    while (i--)        iModulus *= 10;    if (iValue < 0)        iAbsValue = -iValue;    else        iAbsValue = iValue;    if (iModulus != 1)    {        iFraction = iAbsValue % iModulus;        iAbsValue = (iAbsValue - iFraction) / iModulus;        if (iValue < 0)            iValue = -iAbsValue;        else            iValue = iAbsValue;    }    else    {        iFraction = 0;    }    iModulus = 10;    i = 1;    while (iModulus <= iValue && iModulus > 0)    {        i++;        iModulus *= 10;    }    if (iValue < 0)        i++;    iCharacters = i + iPrec + (iPrec ? 1 : 0);    if (iCharacters < iWidth)        PadSpaces(pfdata, iWidth - iCharacters);    sprintf(achBuffer, "%ld", iValue);    (*pfdata->func)(pfdata->pvDest, achBuffer, i);    if (iPrec)    {        (*pfdata->func)(pfdata->pvDest, ".", 1);        memset(achBuffer, '0', sizeof(achBuffer));        sprintf(achBuffer + iPrec, "%ld", iFraction);        (*pfdata->func)(pfdata->pvDest,            achBuffer + strlen(achBuffer + iPrec), iPrec);    }}voidFormatResult(dbw_formdata *pfdata,        int iWidth,        int iPrec,        int iIndex){    if (iIndex < 1 || !prsltCurrent || iColsCurrent < iIndex)        return;    iIndex--;    if (prsltCurrent[iIndex].iIsNull)    {        PadSpaces(pfdata, iWidth);        return;    }    switch(prsltCurrent[iIndex].type)    {    case DBWT_Char:        FormatChar(pfdata, prsltCurrent[iIndex].pchCharValue, iWidth, iPrec);        break;    case DBWT_Int:        FormatInteger(pfdata, prsltCurrent[iIndex].iIntValue,            iWidth, 0);        break;    case DBWT_Dec:        FormatInteger(pfdata, prsltCurrent[iIndex].iIntValue,            iWidth, prsltCurrent[iIndex].iScale);        break;    case DBWT_Float:        FormatFloat(pfdata, prsltCurrent[iIndex].fValue,            iWidth,            iPrec == -1 ? prsltCurrent[iIndex].iScale : iPrec);        break;    }}voidFormatHeading(dbw_formdata *pfdata,        int iWidth,        int iPrec,        int iIndex){    if (iIndex < 1 || !prsltCurrent || iColsCurrent < iIndex)        return;    FormatChar(pfdata, prsltCurrent[iIndex - 1].pchHeading, iWidth, iPrec);}voidFormatArg(dbw_formdata *pfdata,        int iWidth,        int iPrec,        int iIndex){    if (iIndex < 1 || iIndex > nArgs)        return;    FormatChar(pfdata, ppchArgList[iIndex - 1], iWidth, iPrec);}char *FindMatch(    char    *pchStart,        char    *pchBounds,        char    *pchChars){    int    nOpen = 1;    if (*pchStart != pchChars[0])        return 0;    while (++pchStart + 1 < pchBounds)    {        if (*pchStart == '%')        {            if (pchStart[1] == pchChars[0])            {                nOpen++;                pchStart++;            }            else if (pchStart[1] == pchChars[1])            {                if (!--nOpen)                    return pchStart;                pchStart++;            }            else if (isdigit(pchStart[1]))            {                while (++pchStart + 1 < pchBounds &&                    isdigit(pchStart[1]));                if (pchStart < pchBounds && *pchStart == pchChars[0])                    nOpen++;            }            else            {                ++pchStart;            }                    }    }    return 0;}void DoConditionalBounded(dbw_buf pchFormat,            dbw_formdata *pfdata,            char *pchBoundary);void DoFile(dbw_buf pchFormat,        char *pchBoundary,        int iIndex);void DoCommand(dbw_buf pchFormat,        char *pchBoundary);void DoFormVar(char    *pchVarName,        dbw_formdata *pfdata,        char *pchBoundary,        char    cType);void SetFormVar(char    *pchVarName,        char *pchBoundary);voidDoFormattingBounded(dbw_buf pchFormat,        dbw_formdata *pfdata,        char *pchBoundary){    char    *pchNow;    int    iWidth;    int    iPrec;    int    iIndex;    int    iNum;    int    iStage;    char    *pchRemote;    if (!pchFormat)        return;    for (pchNow = pchFormat; pchNow != pchBoundary; pchNow++)    {        if (*pchNow == '%')        {            if (pchNow != pchFormat)            {                (*pfdata->func)(pfdata->pvDest, pchFormat, pchNow - pchFormat);                pchFormat = pchNow;            }            pchNow++;            if (pchNow == pchBoundary)                break;            iWidth = 0;            iPrec = -1;            iIndex = -1;            if (*pchNow == '.')            {                pchNow++;                iStage = 1;            }            else            {                iStage = 0;            }            while (pchNow != pchBoundary && isdigit(*pchNow))            {                iNum = 0;                while (pchNow != pchBoundary && isdigit(*pchNow))                {                    iNum *= 10;                    iNum += *pchNow - '0';                    pchNow++;                }                if (pchNow == pchBoundary)                    break;                if ((*pchNow == '.' ||                     *pchNow == ':')                    && iStage == 0)                {                    iWidth = iNum;                    iStage = 1;                    pchNow++;                }                else if (*pchNow == ':' &&                     iStage == 1)                {                    iPrec = iNum;                    iStage = 2;                    pchNow++;                }                else if (*pchNow && iStage < 3)                {                    iIndex = iNum;                    iStage = 3;                }            }            if (pchNow == pchBoundary)                break;            switch (*pchNow)            {            case '%':                (*pfdata->func)(pfdata->pvDest, "%", 1);                break;            case '$':                FormatInteger(pfdata, iPid, iWidth, 0);                break;            case '#':                FormatInteger(pfdata, iSequence, iWidth, 0);            case 'd':                FormatResult(pfdata, iWidth, iPrec, iIndex);                break;            case 'h':                FormatHeading(pfdata, iWidth, iPrec, iIndex);                break;            case 'a':                FormatArg(pfdata, iWidth, iPrec, iIndex);                break;            case 'e':                if (pchErrMsgCurrent)                    FormatChar(pfdata, pchErrMsgCurrent, iWidth, iPrec);                break;            case 'c':                if (pchSQLCurrent)                    FormatChar(pfdata, pchSQLCurrent, iWidth, iPrec);                break;            case 'n':                FormatInteger(pfdata, iErrNoCurrent, iWidth, 0);                break;            case 'v':                if (pchValueCurrent)                    FormatChar(pfdata, pchValueCurrent,                            iWidth, iPrec);                break;            case '{':                pchRemote = FindMatch(pchNow, pchBoundary, "{}");                if (pchRemote)                {                    dbw_formdata fdata;                    int    iOld;                    iOld = iEscaping;                    iEscaping = 1;                    fdata.func = EscapedDataToOutput;                    fdata.pvDest = pfdata;                    DoFormattingBounded(pchNow + 1,                            &fdata,                            pchRemote);                    iEscaping = iOld;                    pchNow = pchRemote + 1;                }                break;            case '(':                if (iIndex < 1 ||                    !prsltCurrent ||                    iColsCurrent < iIndex ||                    !(pchRemote = FindMatch(pchNow, pchBoundary, "()")))                    break;                if (!prsltCurrent[iIndex - 1].iIsNull)                    DoFormattingBounded(pchNow + 1,                        pfdata,                        pchRemote);                pchNow = pchRemote + 1;                break;            case '[':                pchRemote = FindMatch(pchNow, pchBoundary, "[]");                pchNow++;                if (pchNow >= pchBoundary)                    break;                if (pchRemote <= pchNow || !pchRemote)                    break;                switch (*pchNow)                {                case '!':                    DoConditionalBounded(pchNow + 1,                            pfdata,                            pchRemote);                    break;                case '@':                    DoFile(pchNow + 1,                           pchRemote,                           iIndex);                    break;                case '|':                    DoCommand(pchNow + 1,                            pchRemote);                    break;                case '"':                case '\'':                case '\\':                    {                        dbw_formdata fdata;                            if (*pchNow == '\'')                            fdata.func =                               DoubleUpSQuotes;                        else if (*pchNow == '"')                            fdata.func =                               DoubleUpDQuotes;                        else if (*pchNow == '\\')                            fdata.func =                               DoubleUpBackSlashes;                        fdata.pvDest = pfdata;                        DoFormattingBounded(pchNow + 1,                                &fdata,                                pchRemote);                        pchNow = pchRemote + 1;                    }                    break;                case '-':                    {                        int    iOld;                        iOld = iInternal;                        iInternal = 0;                        DoFormattingBounded(pchNow + 1,                                pfdata,                                pchRemote);                        pchNow = pchRemote + 1;                        iInternal = iOld;                    }                    break;                case '=':    /* Sub value */                case '~':    /* Sub if no value */                case '?':    /* Sub if has value */                    DoFormVar(pchNow + 1,                        pfdata,                        pchRemote,                        *pchNow);                    pchNow = pchRemote + 1;                    break;                case '*':    /* Set variable */                    SetFormVar(pchNow + 1,                        pchRemote);                    pchNow = pchRemote + 1;                    break;                }                pchNow = pchRemote + 1;                break;            }            pchFormat = pchNow + 1;        }    }    if (pchFormat != pchNow)        (*pfdata->func)(pfdata->pvDest, pchFormat, pchNow - pchFormat);}/* The inclusion of "Char" in DBW_IS_BINARY is for the benefit * of databases which do not have binary datatypes. They can store * binary data as hexadecimal or uuencoded character fields, * use the "%n[@file%]" feature to save this to a file, then use * the "%[|command%]" feature to convert it to binary */#define    DBW_IS_BINARY(x)    ((x) == DBWT_Raw || \                 (x) == DBWT_Raw_Sidx || \                 (x) == DBWT_Raw_Lidx || \                 (x) == DBWT_Char)voidDoFile(dbw_buf pchFormat,    char *pchBoundary,    int iIndex){    dbw_formdata fdata;    dbw_string str;    FILE    *fp;    if (!prsltCurrent ||        iIndex < 1 ||        iIndex > iColsCurrent ||        !DBW_IS_BINARY(prsltCurrent[iIndex - 1].type) ||        pchBoundary <= pchFormat)        return;    str.iBytes = 256;    str.iLen = 0;    str.pchData = new2(char, 256);    str.pchData[0] = 0;    fdata.func = DataToString;    fdata.pvDest = &str;    DoFormattingBounded(pchFormat, &fdata, pchBoundary);    fp = fopen(str.pchData,#ifdef _Windows            "wb");#else            "w");#endif    if (fp)    {        switch(prsltCurrent[iIndex - 1].type)        {        case DBWT_Raw:            fwrite(prsltCurrent[iIndex - 1].pchCharValue,                1,                prsltCurrent[iIndex - 1].iScale,                fp);            break;        case DBWT_Raw_Sidx:            fwrite(prsltCurrent[iIndex - 1].pchCharValue + sizeof(short),                1,                *(unsigned short *) prsltCurrent[iIndex - 1].pchCharValue,                fp);            break;        case DBWT_Raw_Lidx:            fwrite(prsltCurrent[iIndex - 1].pchCharValue + sizeof(long),                1,                *(unsigned long *) prsltCurrent[iIndex - 1].pchCharValue,                fp);            break;        case DBWT_Char:            fwrite(prsltCurrent[iIndex - 1].pchCharValue,                1,                strlen(prsltCurrent[iIndex - 1].pchCharValue),                fp);        }        fclose(fp);    }    free(str.pchData);}voidDoCommand(dbw_buf pchFormat,    char *pchBoundary){#ifndef _Windows    dbw_formdata fdata;    dbw_string str;    if (pchBoundary <= pchFormat)        return;    str.iBytes = 256;    str.iLen = 0;    str.pchData = new2(char, 256);    str.pchData[0] = 0;    fdata.func = DataToString;    fdata.pvDest = &str;    DoFormattingBounded(pchFormat, &fdata, pchBoundary);    system(str.pchData);    free(str.pchData);#endif}voidDoConditionalBounded(dbw_buf pchFormat,        dbw_formdata *pfdata,        char *pchBoundary){    int    iNum;    int    iGo = 0;    while (pchFormat != pchBoundary && *pchFormat != ':')    {        if (!isdigit(*pchFormat))            return;        iNum = 0;        while (pchFormat != pchBoundary && isdigit(*pchFormat))        {            iNum *= 10;            iNum += *pchFormat - '0';            pchFormat++;        }        if (pchFormat == pchBoundary ||            (*pchFormat != ':' &&             *pchFormat != ','))            return;        if (iNum < 1 || iNum > iColsCurrent)            return;        if (!prsltPrevious || !piAreRepeats[iNum - 1])            iGo = 1;        if (*pchFormat == ',')            pchFormat++;    }    if (pchFormat >= pchBoundary)        return;    pchFormat++;    if (!iGo)        return;    DoFormattingBounded(pchFormat, pfdata, pchBoundary);}voidSetFormVar(char *pchVarName,    char    *pchBoundary){    char    *pchVarEnd;    dbw_formdata fdata;    dbw_string str;    dbw_value *pval;    for (pchVarEnd = pchVarName;         pchVarEnd != pchBoundary && *pchVarEnd != ':';         pchVarEnd++);    if (pchVarEnd == pchBoundary)        return;    str.iBytes = 256;    str.iLen = 0;    str.pchData = new2(char, 256);    str.pchData[0] = 0;    fdata.func = DataToString;    fdata.pvDest = &str;    *pchVarEnd++ = 0;    DoFormattingBounded(pchVarEnd, &fdata, pchBoundary);    pval = new(dbw_value);    pval->pchKey = StringDuplicate(pchVarName);    pval->pchValue = str.pchData;    pval->pvalNext = pvalForm;    pvalForm = pval;}voidDoFormVar(char    *pchVarName,    dbw_formdata *pfdata,    char *pchBoundary,    char    cType){    int    iNum;    char    *pchColon;    char    *pchVarCopy;    char    *pchValue;    for (pchColon = pchVarName;         pchColon != pchBoundary &&           *pchColon != ':';         pchColon++);    if (cType != '=' && pchColon == pchBoundary)        return;    pchVarCopy = new2(char, (pchColon - pchVarName) + 1);    memcpy(pchVarCopy, pchVarName, pchColon - pchVarName);    pchVarCopy[pchColon - pchVarName] = 0;    pchValue = GetValue(pvalForm, pchVarCopy);    free(pchVarCopy);    if (pchValue)    {        switch(cType)        {        case '=':            FormatChar(pfdata, pchValue, 0, -1);            break;        case '?':            DoFormattingBounded(pchColon + 1, pfdata, pchBoundary);            break;        }    }    else    {        switch(cType)        {        case '=':            if (pchColon == pchBoundary)                break;        case '~':            DoFormattingBounded(pchColon + 1, pfdata, pchBoundary);            break;        }    }    FreeString(pchValue);}voidDoFormatting(dbw_buf pchFormat, dbw_formdata *pfdata){    if (!pchFormat)        return;    DoFormattingBounded(pchFormat, pfdata, pchFormat + StringLength(pchFormat));}voidFormattedWrite(dbw_buf pchFormat){    dbw_formdata fdata;    fdata.func = DataToOutput;    fdata.pvDest = fpOutput;    DoFormatting(pchFormat, &fdata);}dbw_bufConvertFormat(dbw_buf pchFormat){    dbw_formdata fdata;    dbw_string str;    str.iBytes = 256;    str.iLen = 0;    str.pchData = new2(char, 256);    str.pchData[0] = 0;    fdata.func = DataToString;    fdata.pvDest = &str;    iInternal = 1;    DoFormatting(pchFormat, &fdata);    iInternal = 0;    return str.pchData;}voidFormatOutput(    dbw_result *prslt,        int    iColumns){    int    i;    prsltCurrent = prslt;    iColsCurrent = iColumns;    if (prsltPrevious)    {        if (!piAreRepeats)            piAreRepeats = new2(int, iColumns);        for (i = 0; i < iColumns; i++)        {            if (prslt[i].iIsNull || prsltPrevious[i].iIsNull)            {                piAreRepeats[i] = (prslt[i].iIsNull &&                        prsltPrevious[i].iIsNull);                continue;            }            switch(prslt[i].type)            {            case DBWT_Char:                piAreRepeats[i] =                     !strcmp(prslt[i].pchCharValue,                    prsltPrevious[i].pchCharValue);                break;            case DBWT_Float:                piAreRepeats[i] =                    (prslt[i].fValue ==                    prsltPrevious[i].fValue);                break;            case DBWT_Int:                piAreRepeats[i] =                    (prslt[i].iIntValue ==                    prsltPrevious[i].iIntValue);                break;            default:                piAreRepeats[i] = 0;                break;            }        }    }    FormattedWrite(pchFormat);    prsltCurrent = 0;    iColsCurrent = 0;    if (!prsltPrevious)    {        prsltPrevious = new2(dbw_result, iColumns);        nColsPrevious = iColumns;        for (i = 0; i < iColumns; i++)        {            if (prslt[i].type == DBWT_Char)            {                prsltPrevious[i].pchCharValue =                    new2(char, prslt[i].iScale);            }            else            {                prsltPrevious[i].pchCharValue = 0;            }        }    }    for (i = 0; i < iColumns; i++)    {        prsltPrevious[i].iIsNull = prslt[i].iIsNull;        if (prslt[i].iIsNull)            continue;        switch(prslt[i].type)        {        case DBWT_Char:            strcpy(prsltPrevious[i].pchCharValue,                prslt[i].pchCharValue);            break;        case DBWT_Float:            prsltPrevious[i].fValue = prslt[i].fValue;            break;        case DBWT_Int:            prsltPrevious[i].iIntValue = prslt[i].iIntValue;                break;        }    }#ifdef _Windows    FlushMessages();#endif    iSequence++;}voidFormatHeadings(    dbw_result *prslt,        int    iColumns){    prsltCurrent = prslt;    iColsCurrent = iColumns;    FormattedWrite(pchHeadings);    prsltCurrent = 0;    iColsCurrent = 0;}voidFormatErrors(    long    iErrNo,        dbw_buf    pchErrMsg,        dbw_buf    pchSQL){    iErrNoCurrent = iErrNo;    pchErrMsgCurrent = pchErrMsg;    pchSQLCurrent = pchSQL;    FormattedWrite(pchError);    iErrNoCurrent = 0;    pchErrMsgCurrent = 0;    pchSQLCurrent = 0;}char    *CopyUnescaped(char *pchData){    char    *pchTemp;    char    *pchOut;    int    iBytes;    char    c;    for (pchTemp = pchData, iBytes = 0;         *pchTemp;         iBytes++, GetNextEscape(&pchTemp));    pchOut = new2(char, iBytes + 1);    pchTemp = pchOut;    while (*pchData)        *pchTemp++ = GetNextEscape(&pchData);    *pchTemp = 0;    return pchOut;}voidReadVariables(    int iContentLength,        FILE    *fp){    char    *pchData;    char    *pchVar;    char    *pchVal;    char    *pchEnd;    dbw_value *pval;    pchData = new2(char, iContentLength + 1);    fread(pchData, 1, iContentLength, fp);    pchData[iContentLength] = 0;    pchVar = pchData;    while (*pchVar)    {        pchVal = pchVar;        while (*pchVal != '=' &&               *pchVal != '&' &&               *pchVal)            pchVal++;        if (!*pchVal)            break;        if (*pchVal == '&')        {            pchVar = pchVal + 1;            continue;        }        *pchVal++ = 0;        pchEnd = pchVal;        while (*pchEnd != '&' &&               *pchEnd)            pchEnd++;        if (*pchEnd)            *pchEnd++ = 0;        pchVal = CopyUnescaped(pchVal);        pchVar = CopyUnescaped(pchVar);        pval = new(dbw_value);        pval->pchKey = pchVar;        pval->pchValue = pchVal;        pval->pvalNext = pvalForm;        pvalForm = pval;        pchVar = pchEnd;    }    free(pchData);}#ifdef _Windowsint    CALLBACKWinMain(HINSTANCE    hInstance,    HINSTANCE    hPrec,    LPSTR        lpCmdLine,    int        nShow)#elseintmain(int argc, char **argv)#endif{#ifdef _Windows    static char pchServerProtocol[80],        pchServerSoftware[256],        pchPath[256],        pchArgsBuf[1024],        pchContentLength[80];    char    *pchDataFile,        *pchOutput,        *pchContentFile,        *pchArgs;#else    char    *pchServerProtocol,        *pchServerSoftware,        *pchContentLength,        *pchArgs,        *pchPath;#endif    int    i;    int    iArg;    char    *c, *c2;#ifdef _Windows    pchDataFile = lpCmdLine;    c = strchr(lpCmdLine, ' ');    if (!c)        return 1;    *c++ = 0;    pchContentFile = c;    c = strchr(c, ' ');    if (!c)        return 1;    *c++ = 0;    pchOutput = c;    c = strchr(c, ' ');    if (c)        *c = 0;    pchArgs = pchArgsBuf;    GetPrivateProfileString("CGI", "Request Protocol", "HTTP/1.0", pchServerProtocol, 80, pchDataFile);    GetPrivateProfileString("CGI", "Server Software", "Unknown", pchServerSoftware, 256, pchDataFile);    GetPrivateProfileString("CGI", "Query String", "", pchArgs, 256, pchDataFile);    GetPrivateProfileString("CGI", "Physical Path", "", pchPath, 256, pchDataFile);    GetPrivateProfileString("CGI", "Content Length", "", pchContentLength, 80, pchDataFile);    if (*pchContentLength)    {        FILE    *fp = fopen(pchContentFile, "rb");        ReadVariables(atoi(pchContentLength), fp);        fclose(fp);    }    fpOutput = fopen(pchOutput, "wb");    iPid = (long) hInstance;#else    fpOutput = stdout;    pchServerProtocol = getenv("SERVER_PROTOCOL");    pchServerSoftware = getenv("SERVER_SOFTWARE");    pchContentLength = getenv("CONTENT_LENGTH");    pchPath = getenv("PATH_TRANSLATED");    pchArgs = getenv("QUERY_STRING");    if (pchContentLength)        ReadVariables(atoi(pchContentLength), stdin);    iPid = getpid();#endif    fprintf(fpOutput,        "%s 200 Document follows\r\n"        "MIME-Version: 1.0\r\n"        "Server: %s * dbcgi\r\n"        "Content-Type: text/html\r\n\r\n",        pchServerProtocol,        pchServerSoftware);    if (!pchArgs || !*pchArgs)    {        ppchArgList = 0;        nArgs = 0;    }    else    {        nArgs = 1;        for (c = pchArgs; *c; c++)            if (*c == '+')                nArgs++;        ppchArgList = new2(char *, nArgs);        c = pchArgs;        iArg = 0;        do        {            if (*c == '+' || !*c)            {                for (c2 = pchArgs, i = 0;                     c2 < c;                      i++)                    GetNextEscape(&c2);                ppchArgList[iArg] = new2(char, i + 1);                for (c2 = pchArgs, i = 0;                     c2 < c;                      i++)                {                    ppchArgList[iArg][i] =                        GetNextEscape(&c2);                }                ppchArgList[iArg][i] = 0;                iArg++;                pchArgs = c2 + 1;            }        }        while (*c++);    }    pchError = StringDuplicate("<H1>Error</H1>"            "Error %n \"%e\" occurred in<BR>"            "<STRONG>%c</STRONG><BR>"            "---- End of error ----<BR>");    ReadFile(pchPath);    return 0;}voidFreeString(char *pchData){    if (pchData)        free(pchData);}voidPutEnvVar(char const *pchVariable,    char const *pchValue){    if (pchVariable && pchValue)    {        char    *pchBuffer;        pchBuffer = new2(char, strlen(pchVariable) + strlen(pchValue) + 2);        strcpy(pchBuffer, pchVariable);        strcat(pchBuffer, "=");        strcat(pchBuffer, pchValue);        putenv(pchBuffer);        /* Note that we must *not* free pchBuffer */    }}dbw_bindinfo *FindColInfo(    dbw_typemap *atm,        int iEntries,        dbw_result *prslt,        char const *pchColumn,        int iColType,        int iColumnWidth,        int iColumnPrec){    static    dbw_bindinfo    bi;    while (iEntries--)    {        if (atm->iOrigType == iColType)        {            bi.iBindType = atm->iBindType;            prslt->type = atm->type;            prslt->pchHeading = StringDuplicate(pchColumn);            switch (atm->type)            {            case DBWT_Char:                if (atm->iSize)                    bi.iWidth = atm->iSize;                else                    bi.iWidth = iColumnWidth + 1;                prslt->pchCharValue = new2(char, bi.iWidth);                bi.pchData = prslt->pchCharValue;                prslt->iScale = bi.iWidth - 1;                break;            case DBWT_Int:                bi.iWidth = sizeof(long);                bi.pchData = (char *) &prslt->iIntValue;                prslt->iScale = 0;                break;            case DBWT_Dec:                bi.iWidth = sizeof(long);                bi.pchData = (char *) &prslt->iIntValue;                prslt->iScale = iColumnPrec;                break;            case DBWT_Float:                bi.iWidth = sizeof(double);                bi.pchData = (char *) &prslt->fValue;                prslt->iScale = iColumnPrec;                break;            case DBWT_Raw:                if (atm->iSize)                    bi.iWidth = atm->iSize;                else                    bi.iWidth = iColumnWidth;                prslt->pchCharValue = new2(char, bi.iWidth);                bi.pchData = prslt->pchCharValue;                prslt->iScale = iColumnWidth;                break;            case DBWT_Raw_Sidx:                if (atm->iSize)                    bi.iWidth = atm->iSize + sizeof(short);                else                    bi.iWidth = iColumnWidth + sizeof(short);                prslt->pchCharValue = new2(char, bi.iWidth);                bi.pchData = prslt->pchCharValue;                prslt->iScale = iColumnWidth;                break;            case DBWT_Raw_Lidx:                if (atm->iSize)                    bi.iWidth = atm->iSize + sizeof(long);                else                    bi.iWidth = iColumnWidth + sizeof(long);                prslt->pchCharValue = new2(char, bi.iWidth);                bi.pchData = prslt->pchCharValue;                prslt->iScale = iColumnWidth;                break;            }            return &bi;        }        atm++;    }    return 0;}char    *GetValue(    dbw_value *pval,        char const *pchKey){    while (pval && !StringCompare(pval->pchKey, pchKey, 256))        pval = pval->pvalNext;    if (pval)        return StringDuplicate(pval->pchValue);    return 0;}struct __dbw_conninfo *FindConnection(dbw_value *pval){    char    *pchConnID = GetValue(pval, "ConnID");    dbw_connection *pconn;    if (!pchConnID)    {        FormatErrors(0, "No connection ID specified", "Syntax");        return 0;    }    for (pconn = pconnList;         pconn && strcmp(pconn->pchConnID, pchConnID);         pconn = pconn->pconnNext);    if (!pconn)        FormatErrors(0, "No such connection", pchConnID);    FreeString(pchConnID);    return pconn ? pconn->pci : 0;}intAddConnection(dbw_value *pval,        struct __dbw_conninfo *pinfo){    char    *pchConnID = GetValue(pval, "ConnID");    dbw_connection *pconn = new(dbw_connection);    if (!pchConnID)    {        FormatErrors(0, "No connection ID specified", "Syntax");        free(pconn);        return 0;    }    pconn->pconnNext = pconnList;    pconn->pci = pinfo;    pconn->pchConnID = pchConnID;    pconnList = pconn;    return 1;}voidDropConnection(dbw_value *pval){    char    *pchConnID = GetValue(pval, "ConnID");    dbw_connection **ppconn, *pconn;    if (!pchConnID)    {        FormatErrors(0, "No connection ID specified", "Syntax");        return;    }    for (ppconn = &pconnList;         *ppconn && strcmp((*ppconn)->pchConnID, pchConnID);         ppconn = &(*ppconn)->pconnNext);    if (*ppconn)    {        pconn = (*ppconn)->pconnNext;        free((*ppconn)->pci);        free((*ppconn)->pchConnID);        free(*ppconn);        *ppconn = pconn;    }    else    {        FormatErrors(0, "No such connection", pchConnID);    }    FreeString(pchConnID);}#ifdef _Windowsvoid    FlushMessages(){    MSG    msg;        while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))    {        TranslateMessage( &msg );        DispatchMessage( &msg );    }}#endif